package gwtlx.util.client;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * JsLinkedMap is a lightweight pseudo-map implementation, similar to {@link java.util.LinkedHashMap}.
 *
 * It provides functionality similar to the {@link java.util.List}
 * and {@link java.util.Map} at the same time.
 *
 * There are key accessors as well as index accessors.
 *
 * This implementation maintains a doubly-linked array containing all of its entries.
 * This array is normally has order in which keys were inserted into the map
 * (<i>insertion-order</i>).
 *
 * @author Konstantin Pavlov
 * @version $LastChangedRevision: 20 $
 * @since 26.01.11
 */
public class JsLinkedMap extends JavaScriptObject {

    /** Every {@link JavaScriptObject} must have such constructor. */
    protected JsLinkedMap() {
    }

    public static JsLinkedMap as(JavaScriptObject javaScriptObject) {
        return (JsLinkedMap) javaScriptObject;
    }

    /**
     * Creates new {@link JsLinkedMap} object.
     *
     * @return new empty {@link JsLinkedMap}
     */
    public static native JsLinkedMap newInstance() /*-{
        var o = {ar:[],mp:{}};
        return @gwtlx.util.client.JsLinkedMap::as(Lcom/google/gwt/core/client/JavaScriptObject;)(o);
    }-*/;


    public static native void set(int index, Object value) /*-{
        this.ar[index] = value;
    }-*/;

    /**
     * Map-like interface
     *
     * @param key   key
     * @param value value to put
     *
     * @throws IllegalArgumentException if key value is 'arr
     */
    public static native void put(String key, Object value) throws IllegalArgumentException/*-{
        this.mp[key] = value;
        this.ar[this.ar.length] = value;
    }-*/;

    /**
     * Returns map size
     *
     * @return map size
     */
    public static native int size() /*-{
        return this.ar.length;
    }-*/;

    /**
     * Returns map size
     *
     * @param index element index
     *
     * @return stored object
     *
     * @throws ArrayIndexOutOfBoundsException if index is our of range
     */
    public static native JavaScriptObject get(int index) throws ArrayIndexOutOfBoundsException/*-{
        if (index >= 0 && index < this.ar.length) {
            return this.ar[index];
        } else {
            throw new @java.lang.ArrayIndexOutOfBoundsException::new(I)(index);
        }
    }-*/;

    /**
     * Returns map element by specified key
     *
     * @param key object key
     *
     * @return object by key or null
     */
    public static native JavaScriptObject get(String key) /*-{
        if (!!this.mp[key]) {
            return this.mp[key];
        } else {
            return null;
        }

    }-*/;

    /**
     *
     * This linked list defines the iteration ordering,
 * which is normally the order in which keys were inserted into the map
 * (<i>insertion-order</i>).
     * Returns array of values ordered
     *
     * @return Array of values sorted by  order of addition
     */
    public static native Object[] values() /*-{
        return this.ar;
    }-*/;


}
